using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Pazinga
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Pazinga : Microsoft.Xna.Framework.Game
    {

        #region declaration

        public Rectangle TankRec 
        {
            get { return new Rectangle((int)Tank_Xspace,440,80,30); }
        }

        GraphicsDeviceManager graphics;

        SpriteBatch spriteBatch;

        //the game stat enum object deciding game state
        GameState gameState;

        //MouseState object hold the mouse state and click information
        MouseState Click;

        //MouseState object that store mouse previous state
        MouseState PrevState;

        SoundEffect FighterFireSound;

        SoundEffect TankFireSound;

        SoundEffect ExplodeSound;

        SpriteFont BigFont;

        //float variable that hold the tank's x space.
        float Tank_Xspace;

        //List of Air Fighters
        public List<Fighter> Fighters;

        //List of Missle fires
        List<MissleFire> Missles;

        //List of TankFire objects
        List<TankFire> TankFires;

        //The Tank object
        Tank Tank_Obj;

        //Texture2D object that will hold the pazinga text logo image
        Texture2D PazingaText;

        //Texture2D Tank Fire
        Texture2D TankFire;             

        //Texture2d object that will hold the playing background image 
        Texture2D TierBackground;

        //Texture2D object that will hold the player tank
        Texture2D Texture_Tank;

        //Texture2d that will hold Button texture
        Texture2D MovementButtonTexture;

        //Texture2D that will hold the fire button Texture
        Texture2D FireButton;

        //Texture2D Fighter [F1]
        Texture2D F1_Fighter;

        //Texture2D of missles
        Texture2D MissleTexture;

        SpriteFont SmallFont;

        #endregion

        /// <summary>
        /// Create new pazinga game object
        /// </summary>
        public Pazinga()
        {
            //initialize the game graphics manager
            graphics = new GraphicsDeviceManager(this);

            //set content root directoory
            Content.RootDirectory = "Content";

            //initialize fighters list
            Fighters = new List<Fighter>();

            //Add some fighters
            Fighters.Add(new Fighter(-15.5f,80,28));

            Fighters.Add(new Fighter(-5.5f, 80, 28));

            Fighters.Add(new Fighter(-10.5f, 80, 28));

            //initialize missle fire objects
            Missles = new List<MissleFire>();

            //initialize tankfire objects
            TankFires = new List<TankFire>();

            //Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);

            //initialize the value of the tank object
            Tank_Obj = new Tank();
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            gameState = GameState.Play;

            //initialite mouse state
            Click = Mouse.GetState();

            //Initialize Mouse Prevoius state
            PrevState = Click;

            //initialize tank X space
            Tank_Xspace = 200;

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {

            ExplodeSound = Content.Load<SoundEffect>("Explode");

            TankFireSound = Content.Load<SoundEffect>("TankFire");

            FighterFireSound = Content.Load<SoundEffect>("FighterFire");

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //Load Fire button Texture
            FireButton = Content.Load<Texture2D>("FireButton");

            BigFont = Content.Load<SpriteFont>("HeaderFont");

            //Load pazinga text logo texture
            PazingaText = Content.Load<Texture2D>("Pazinga");

            //Load tank gun fire Texture2D
            TankFire = Content.Load<Texture2D>("Missels\\T1");

            MissleTexture = Content.Load<Texture2D>("Missels\\M1");


            //Load the tank texture
            Texture_Tank = Content.Load<Texture2D>("Tank");
            
            //Load F1 Air FighterS
            F1_Fighter = Content.Load<Texture2D>("AirFighters\\A6");

            //Load Buttton Texture
            MovementButtonTexture = Content.Load<Texture2D>("MovementButton");

            //Load the playing background texture
            TierBackground = Content.Load<Texture2D>("Tier");

            SmallFont = Content.Load<SpriteFont>("SmallFont");
            
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {

            if (Tank_Obj.RemainAmmo == 0 && TankFires.Count==0)
            {
                gameState = GameState.GameOver;
            }

            //Refresh mouse state by getting current state
            Click = Mouse.GetState();

            switch (gameState) 
            {
                case GameState.Menu:
                    break;

                case GameState.Play:
                    //Check if the mouse clicks on the right movement button 
                    if (Click.LeftButton == ButtonState.Pressed && IsMouseOnRightButton(Click))
                    {
                        //set the new x value for the tank and avoid get out from the right side
                        Tank_Xspace = (Tank_Xspace + 15f) > 630 ? Tank_Xspace : (Tank_Xspace + 15f);
                        
                    }

                    //Check if the mouse clicks on the right movement button 
                    if (Click.LeftButton == ButtonState.Pressed && IsMouseOnLeftButton(Click))
                    {
                        //set the new x value for the tank and avoid get out from the left side
                        Tank_Xspace = (Tank_Xspace + 15f) < 100 ? Tank_Xspace : (Tank_Xspace - 15f);
                        
                    }

                    //Check if the right gun fire button is pressed after being released
                    if (Click.LeftButton == ButtonState.Pressed && IsMouseOnRightFireButton(Click) &&PrevState.LeftButton==ButtonState.Released)
                    {
                        FireRightTankWeapon();
                    }

                    //Check if the Left gun fire button is pressed after being released
                    if (Click.LeftButton == ButtonState.Pressed && IsMouseOnLeftFireButton(Click) && PrevState.LeftButton == ButtonState.Released)
                    {
                        FireLeftTankWeapon();
                    }

                    //Update Air Fighters
                    foreach (var a in Fighters)
                    {
                        a.update();
                    }

                    //Loop on Tank Gun Fire objects and update them
                    foreach (var a in TankFires)
                    {
                        //Check if the gun fire still in the game view port
                        if (a.Y > -30)
                        {
                            //Update tank gun fire object
                            a.Update();
                        }
                    }

                    FighterCloseobTankAndFire();

                    //check for missed gun fire and removing them
                    for (int i = 0; i < TankFires.Count; i++)
                    {
                        var shot=TankFires[i];

                        if (shot.Y < -30)
                        {
                            TankFires.Remove(shot);
                        }
                    }

                    //update missles
                    foreach (var mis in Missles)
                    {
                        mis.Update();
                    }

                    for (int i = 0; i < Missles.Count; i++)
                    {
                        var shot = Missles[i];

                        if (shot.Y > 500)
                        {
                            Missles.Remove(shot);
                        } 
                    }

                        CheckCollisions();

                    break;
            }

            //Set the Previous state value
            PrevState = Click;

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
            
            spriteBatch.Begin();

            switch (gameState)
            {
                case GameState.Start:
                    spriteBatch.Draw(PazingaText, new Rectangle(0, 0, 800, 480), Color.Red);
                    break;

                case GameState.Loading:
                    spriteBatch.Draw(PazingaText, Vector2.Zero, Color.CornflowerBlue);
                    break;

                case GameState.Play:
                    //Draw the background texture
                    spriteBatch.Draw(TierBackground,new Rectangle(0,0,800,480), Color.White);

                    //Draw the tank
                    spriteBatch.Draw(Texture_Tank, new Vector2((int)(Tank_Xspace),440), Color.White);

                    //Draw Air Fighters
                    foreach (var a in Fighters)
                    {
                        a.DrawFighter(spriteBatch,F1_Fighter);

                        if (a.X > 900)
                            a.X = -200;
                    }

                    //Draw Tank Fire
                    foreach (var a in TankFires)
                    {
                        a.DrawTankFire(spriteBatch, TankFire);
                    }

                    foreach (var mis in Missles)
                    {
                        mis.DrawMissleFire(spriteBatch, MissleTexture);
                    }

                    //Draw movement right button
                    spriteBatch.Draw(MovementButtonTexture, new Rectangle(720, 400,80,80), Color.White);

                    //Draw movement left button
                    spriteBatch.Draw(MovementButtonTexture, new Rectangle(0,400,80,80), null, Color.White,0,Vector2.Zero,SpriteEffects.FlipHorizontally,0);

                    //Draw Fire right button
                    spriteBatch.Draw(FireButton, new Rectangle(720, 320, 80, 80), Color.White);

                    //Draw Fire right button
                    spriteBatch.DrawString(SmallFont, Tank_Obj.RightFireCount.ToString(), new Vector2(750, 340),Color.Black);

                    //Draw Fire left button
                    spriteBatch.Draw(FireButton, new Rectangle(0, 320, 80, 80), null, Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);

                    //Draw Fire right button
                    spriteBatch.DrawString(SmallFont, Tank_Obj.LeftFireCount.ToString(), new Vector2(30, 340), Color.Black);

                    break;

                    

                case GameState.GameOver:

                    //Draw the background texture
                    spriteBatch.Draw(TierBackground, new Rectangle(0, 0, 800, 480), Color.White);

                    //Draw the tank
                    spriteBatch.Draw(Texture_Tank, new Vector2((int)(Tank_Xspace), 440), Color.White);

                    //Draw Air Fighters
                    foreach (var a in Fighters)
                    {
                        a.DrawFighter(spriteBatch, F1_Fighter);

                        if (a.X > 900)
                            a.X = -200;
                    }

                    //Draw Tank Fire
                    foreach (var a in TankFires)
                    {
                        a.DrawTankFire(spriteBatch, TankFire);
                    }

                    foreach (var mis in Missles)
                    {
                        mis.DrawMissleFire(spriteBatch, MissleTexture);
                    }

                    //Draw movement right button
                    spriteBatch.Draw(MovementButtonTexture, new Rectangle(720, 400, 80, 80), Color.White);

                    //Draw movement left button
                    spriteBatch.Draw(MovementButtonTexture, new Rectangle(0, 400, 80, 80), null, Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);

                    //Draw Fire right button
                    spriteBatch.Draw(FireButton, new Rectangle(720, 320, 80, 80), Color.White);

                    //Draw Fire right button
                    spriteBatch.DrawString(SmallFont, Tank_Obj.RightFireCount.ToString(), new Vector2(750, 340), Color.Black);

                    //Draw Fire left button
                    spriteBatch.Draw(FireButton, new Rectangle(0, 320, 80, 80), null, Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);

                    //Draw Fire right button
                    spriteBatch.DrawString(SmallFont, Tank_Obj.LeftFireCount.ToString(), new Vector2(30, 340), Color.Black);

                    spriteBatch.DrawString(BigFont,"Game Over", new Vector2(310, 220), Color.Black);

                    break;
            }
        
            //draw the mouse


            spriteBatch.End();
            base.Draw(gameTime);

        }

        //--------------------------------------------------------------------------------------------------//

        private bool IsMouseOnRightButton(MouseState mouseState) 
        {
            //get mouse x axis
            int X_Axis = mouseState.X;

            //get mouse y axis
            int Y_Axis = mouseState.Y;

            //check if the mouse over the right button
            if (Y_Axis > 400 && Y_Axis < 480 && X_Axis > 720 && X_Axis < 800)
                return true;
            else
                return false;
        }

        private bool IsMouseOnLeftButton(MouseState mouseState)
        {
            //get mouse x axis
            int X_Axis = mouseState.X;

            //get mouse y axis
            int Y_Axis = mouseState.Y;

            //check if the mouse over the left button
            if (Y_Axis > 400 && Y_Axis < 480 && X_Axis > 0 && X_Axis < 80)
                return true;
            else
                return false;
        }

        private bool IsMouseOnRightFireButton(MouseState mouseState) 
        {
            //get mouse x axis
            int X_Axis = mouseState.X;

            //get mouse y axis
            int Y_Axis = mouseState.Y;

            //check if the mouse over the right button
            if (Y_Axis > 320 && Y_Axis < 400 && X_Axis > 720 && X_Axis < 800)
                return true;
            else
                return false;
        }

        private bool IsMouseOnLeftFireButton(MouseState mouseState)
        {
            //get mouse x axis
            int X_Axis = mouseState.X;

            //get mouse y axis
            int Y_Axis = mouseState.Y;

            //check if the mouse over the left button
            if (Y_Axis > 320 && Y_Axis < 400 && X_Axis > 0 && X_Axis < 80)
                return true;
            else
                return false;
        }

        private void FireRightTankWeapon() 
        {
            if (Tank_Obj.RightFireCount > 0)
            {
                TankFireSound.Play();

                //Add a fire to TankFire lise with co-ordinates or tank right gun
                TankFires.Add(new TankFire(new Vector2(Tank_Xspace + 82, 440)));

                //decrease the right cannon count
                Tank_Obj.RightFireCount -= 1;
            }
        }

        private void FireLeftTankWeapon()
        {
            if (Tank_Obj.LeftFireCount > 0)
            {

                TankFireSound.Play();
                //Add a fire to TankFire lise with co-ordinates or tank right gun
                TankFires.Add(new TankFire(new Vector2(Tank_Xspace + 5, 440)));

                //decrease one fire from left cannon
                Tank_Obj.LeftFireCount -= 1;
            }
        }

        /// <summary>
        /// Check Collision and do necessary funcitionality
        /// </summary>
        private void CheckCollisions() 
        {
            for (int i = 0; i < Fighters.Count;i++ )
            {
                var fighter = Fighters[i];

                //loop on tank fires
                for (int j=0;j<TankFires.Count;j++)
                {
                    var shoot = TankFires[j];

                    //Check if the tank fire intersect the fighter
                    if (fighter.Area.Intersects(new Rectangle((int)shoot.Position.X, (int)shoot.Position.Y, 5, 5)))
                    {
                        //Remove the fighter
                        Fighters.Remove(fighter);
                        i--;

                        //Remove the tankfire
                        TankFires.Remove(shoot);
                        j--;

                        Tank_Obj.AddAmmo(3);
                    }
                }
            }

            for (int i = 0; i < Missles.Count; i++)
            {
                var misl = Missles[i];

                //Check if the tank have collision with missles
                if (TankRec .Intersects(new Rectangle((int)misl.X, (int)misl.Y, 5, 7)))
                {
                    ExplodeSound.Play();

                    //remove the missle
                    Missles.Remove(misl);

                    gameState = GameState.GameOver;
                }
            }
        }

        /// <summary>
        /// Check for Fighter Colsing on tanks in Vertical space
        /// </summary>
        private void FighterCloseobTankAndFire() 
        {
            for (int i = 0; i < Fighters.Count; i++)
            {
                //get a figher of index i
                var fighter = Fighters[i];

                //Check if the fighter and the tanks are in the same vertial area of 30
                if (Math.Abs(fighter.X - Tank_Xspace) < 30)
                {
                    //Lunch a missle from a fighter
                    FighterLunchMissle(fighter); 
                }
            }
        }

        /// <summary>
        /// Fighter Lunch a Missle
        /// </summary>
        /// <param name="f">The Fighter Object</param>
        public void FighterLunchMissle(Fighter f)
        {
            //Check if fighter still have missles
            if (f.MissleCount > 0)
            {
                
                FighterFireSound.Play();
                Missles.Add(new MissleFire(new Vector2(f.X + f.Width / 2, f.Y + f.Height)));

                f.MissleCount -= 1;
            }
        }
    }
}

